/**
 * 
 */
"use strict";

var toolbar = toolbar || {};

toolbar.selectors = [];
toolbar.selected_by_id = {};
toolbar.removeSelectors = function() {
	var remove = [];
	// collect all
	toolbar.selectors.foreach(function(i, value, first, last) {
		remove.push(value);
	});
	// remove
	remove.foreach(function(i, value, frist, last) {
		value.remove();
	});
	toolbar.selected_by_id = {};
	// hide action selector
	$('#action_selector').children().remove();
	$('#action_selector').hide();
	$('#event_config').children().remove();
	$('#event_config').hide();
};

toolbar.init = function() {
	// tool bar definition
	toolbar.bar = $("#toolbar");
	toolbar.applier = null;
	toolbar.action_selector = null;

	// item action applier field that hovers above the ground
	toolbar.ItemAction = function(col, row, cls) {
		fields.Field.call(this, col, row, "itemaction");
		if (typeof cls === 'string') {
			this.el.addClass(cls);
			this.cls.push(cls);
		}
	};
	toolbar.ItemAction.prototype = new fields.Field();

	// field select
	toolbar.FieldSelect = function(selected_field) {
		if (!selected_field instanceof fields.Field)
			return;
		fields.Field
			.call(this, selected_field.column, selected_field.row, "select");
		this.place(true);
		this.setInnerPos(selected_field.vec2);
		this.selected = selected_field;
		this.el.data('selector', this);
		toolbar.selectors.push(this);
		toolbar.selected_by_id[selected_field.id] = this;
	};
	toolbar.FieldSelect.prototype = new fields.Field();
	toolbar.FieldSelect.prototype.getSelected = function() {
		/**
		 * @return fields.Field
		 */
		return this.selected;
	};
	toolbar.FieldSelect.prototype.remove = function() {
		fields.Field.prototype.remove.call(this);
		toolbar.selectors.remove(this);
		toolbar.selected_by_id[this.selected.id] = undefined;
	};
	toolbar.FieldSelect.prototype.canPlace = function() {
		return true;
	};

	toolbar.SelectAllMoving = function(fn_onclick) {
		// mark all movable
		for ( var id in fields.by_id) {
			var value = fields.by_id[id];
			if (value instanceof movable.Movable && value.moving()) {
				var sel = new toolbar.FieldSelect(value);
				this.push(sel);
				$(sel.el).on('click', function(e) {
					var selector = $(e.currentTarget).data('selector');
					if (selector) {
						var selected = selector.getSelected();
						if (selected)
							fn_onclick.call(selector, selected);
					}
				});
			}
		}
	};
	toolbar.SelectAllMoving.prototype = new Array();

	toolbar.SelectAllNotMoving = function(fn_onclick) {
		// mark all movable
		for ( var id in fields.by_id) {
			var value = fields.by_id[id];
			if (value instanceof movable.Movable && !value.moving()) {
				var sel = new toolbar.FieldSelect(value);
				this.push(sel);
				$(sel.el).on('click', function(e) {
					var selector = $(e.currentTarget).data('selector');
					if (selector) {
						var selected = selector.getSelected();
						if (selected)
							fn_onclick.call(e, selected);
					}
				});
			}
		}
	};
	toolbar.SelectAllNotMoving.prototype = new Array();

	toolbar.SelectAllSwitches = function(fn_onclick) {
		// mark all signals
		for ( var id in fields.by_id) {
			var value = fields.by_id[id];
			if (value instanceof signals.Switch) {
				var sel = new toolbar.FieldSelect(value);
				this.push(sel);
				var thisObj = this;
				$(sel.el).on('click', function(e) {
					var selector = $(e.currentTarget).data('selector');
					if (selector) {
						// clean previous slected
						thisObj.foreach(function(i, value, first, last) {
							value.el.removeClass('selected');
						});
						var selected = selector.getSelected();
						if (selected) {
							selector.el.addClass('selected');
							fn_onclick.call(e, selected);
						}
					}
				});
			}
		}
	};
	toolbar.SelectAllSwitches.prototype = new Array();

	toolbar.SelectAndChooseActions = function(context, fn_onactionselect, action_field) {
		this.context = context;
		this.fn_onactionselect = fn_onactionselect;
		// clear action choose dialog
		if (toolbar.action_selector !== null)
			toolbar.action_selector.close();
		// only one field
		if (action_field !== undefined) {
			if (this.push(action_field))
				this.selectField(action_field);
		} else
			// mark all fields with actions
			for ( var id in fields.by_id) {
				var value = fields.by_id[id];
				this.push(value);
			}
	};
	toolbar.SelectAndChooseActions.prototype = new Array();
	toolbar.SelectAndChooseActions.prototype.close = function() {
		$('#action_selector').children().remove();
		$('#action_selector').hide();
		this.foreach(function(i, value, first, last) {
			value.remove();
		});
		Array.call(this);
	};
	toolbar.SelectAndChooseActions.prototype.selectField = function(selField) {
		var fn_onactionselect = this.fn_onactionselect;
		var selector = toolbar.selected_by_id[selField.id];
		var context = this.context;
		var thisSelectList = this;
		this.foreach(function(i, value, first, last) {
			// remove borders
			value.el.removeClass('selected');
		});
		// clean current selector
		$('#action_selector').children().remove();
		// paint border around selection
		$(selector.el).addClass('selected');
		$('#action_selector').show();
		// add close button
		$('#action_selector').append($('<button>Close</button>')
			.on('click', function(e) {
				e.stopPropagation();
				thisSelectList.close();
			}));
		// show all available actions
		if (selField.actions !== undefined) {
			selField.actions.foreach(function(i, value, first, last) {
				var actionEl = $(value.html);
				actionEl.data('action', value);
				// action select click
				actionEl.on('click', function(e) {
					e.stopPropagation();
					var action = $(e.currentTarget).data('action');
					fn_onactionselect.call(context, action);
				});
				// append action to dialog
				$('#action_selector').append(actionEl);
			});
		}

	};
	toolbar.SelectAndChooseActions.prototype.push = function(field) {
		var value = field;
		if (value instanceof fields.Field && value.actions.length > 0) {
			var sel = new toolbar.FieldSelect(value);
			sel.el.data('selector', sel);
			// append to list
			Array.prototype.push.call(this, sel);
			// append click callback
			var thisSelectList = this;
			$(sel.el).on('click', function(e) {
				e.stopPropagation();
				var selector = $(e.currentTarget).data('selector');
				var selField = selector.getSelected();
				thisSelectList.selectField(selField);
			});
			return true;
		}
		return false;
	};

	/*
	 * TOOL BAR ITEMS
	 */
	toolbar.toolBarEntries = {
		tool_new : {
			cls : undefined,
			el : $('<div class="toolitem">NEW</div>'),
			ypos : undefined,
			applier : function() {
				if (toolbar.applier !== null)
					toolbar.applier.remove();
				fields.init(traintest.ground, traintest.getColumns(), traintest
					.getRows());
				traintest.resume();
				return null;
			},
			apply : function(applier, col, row) {
				return null;
			}
		},
		tool_save : {
			cls : undefined,
			el : $('<div class="toolitem">SAVE</div>'),
			ypos : undefined,
			applier : function() {
				if (toolbar.applier !== null)
					toolbar.applier.remove();
				traintest.save();
				return null;
			},
			apply : function(applier, col, row) {
				return null;
			}
		},
		tool_escape : {
			cls : undefined,
			el : $('<div class="toolitem">X</div>'),
			ypos : undefined,
			applier : function() {
				if (toolbar.applier !== null)
					toolbar.applier.remove();
				toolbar.removeSelectors();
				traintest.resume();
				return null;
			},
			apply : function(applier, col, row) {
				return null;
			}
		},
		tool_delete : {
			cls : 'delete',
			el : $('<div class="toolitem">DEL</div>'),
			ypos : "0px",
			applier : function() {
				traintest.pause();
				return new toolbar.ItemAction(0, 0, 'delete');
			},
			apply : function(applier, col, row) {
				var f = new fields.FieldPosition(col, row).getFields();
				if (f.length > 1)
					f.last().remove();
				// keep applier active
				return applier;
			}
		},
		test_move_velo : {
			cls : 'move',
			el : $('<div class="toolitem">MOVE</div>'),
			ypos : undefined,
			applier : function() {
				// mark all movable
				if ((new toolbar.SelectAllNotMoving(function(mov_field) {
					// start movement
					var reverse = !mov_field.getNext()
						&& mov_field.getPrevius() !== undefined;
					mov_field.move(reverse);

					// resume and remove all other selectors
					toolbar.removeSelectors();
					traintest.resume();
				})).length > 0)
					traintest.pause();
				return null;
			},
			apply : function(applier, col, row) {
				return null;
			}
		},
		test_move_stop : {
			cls : 'stop',
			el : $('<div class="toolitem">STOP</div>'),
			ypos : undefined,
			applier : function() {
				// mark all movable
				if ((new toolbar.SelectAllMoving(function(selected) {
					this.remove();
					selected.stop();
					if (toolbar.selectors.length === 0) {
						toolbar.removeSelectors();
						traintest.resume();
					}
				})).length > 0)
					traintest.pause();
				return null;
			},
			apply : function(applier, col, row) {
				return null;
			}
		},
		switch_rail : {
			cls : 'switchrail',
			el : $('<div class="toolitem">SWITCH</div>'),
			ypos : undefined,
			applier : function() {
				return new toolbar.ItemAction(0, 0, 'switch');
			},
			apply : function(applier, col, row) {
				var rail = new fields.Rail(col, row);
				var f = rail.getSiblings(rail, 2);
				if (f.length > 0) {
					f[0].switchDir();
				}
				// clean up
				rail.remove();
				// keep applier active
				return applier;
			}

		},
		edit_switches : {
			cls : 'switch',
			el : $('<div class="toolitem">EVENT</div>'),
			ypos : undefined,
			applier : function() {
				// remove all selectors
				toolbar.removeSelectors();

				// mark all switches
				if ((new toolbar.SelectAllSwitches(function(selected) {
					var events = selected.getEvents();
					$('#event_config').children().remove();

					// add close button
					$('#event_config').append($('<button>Close</button>')
						.on('click', function(e) {
							toolbar.removeSelectors();
							traintest.resume();
						}));

					// append all possible events into event config field
					events
						.foreach(function(i, value, first, last) {
							var eventEl = $('<div class="event_list_entry"></div>');
							eventEl.data('event', value);
							eventEl.data('source', selected);
							eventEl.append($(value.html));
							// define the action callback
							var makeActionEl = function(action, event) {
								// make element
								var actionEl = $(action.html);
								actionEl.data('action', action);
								actionEl.data('event', event);
								// append delete X button
								actionEl.append($('<button>X</button>').data({
									action : action,
									event : event
								})
									.on('click', function(e) {
										// delete action
										var act = $(e.currentTarget)
											.data('action');
										var evt = $(e.currentTarget)
											.data('event');
										// remove action from event object
										evt.actions.remove(act);
										// remove html presentation
										$(e.currentTarget.parentElement)
											.remove();
									}));
								// click on action to edit
								actionEl
									.on('click', function(e) {
										// edit this action
										var act = $(e.currentTarget)
											.data('action');
										var evt = $(e.currentTarget)
											.data('event');
										// show action selector dialog - edit
										toolbar.action_selector = new toolbar.SelectAndChooseActions(this, function(action) {
											// remind the old index
											var actidx = evt.actions
												.indexOf(act);
											// overwrite entry
											evt.actions[actidx] = action;
											// and its html element
											var actionEl = makeActionEl(action, evt);
											actionEl
												.insertBefore($(e.currentTarget));
											$(e.currentTarget).remove();
											// close the selector
											toolbar.action_selector.close();
										}, fields.by_id[act.field_id]);
									});
								return actionEl;
							};
							// append actions
							value.actions
								.foreach(function(i, action, first, last) {
									// add action into list element
									eventEl.append(makeActionEl(action, value));
								});
							// append action-add-button
							var addBtn = $('<button>+</button>');
							addBtn.data('event', value);
							addBtn
								.on('click', function(e) {
									// show action selector dialog
									toolbar.action_selector = new toolbar.SelectAndChooseActions(this, function(action) {
										// append new action
										value.actions.push(action);
										// and its html element
										var actionEl = makeActionEl(action, value);
										actionEl
											.insertBefore($(e.currentTarget));
										// close the selector
										toolbar.action_selector.close();
									});
								});
							eventEl.append(addBtn);
							$('#event_config').append(eventEl);
						});

					// show the event configuration bar
					$('#event_config').show();

				})).length > 0) {
					// found elements, pause
					traintest.pause();
				}
				return null;
			},
			apply : function(applier, col, row) {
				return null;
			}
		},
		grass : {
			cls : 'fields',
			el : $('<div class="toolitem"></div>'),
			ypos : "-64px",
			applier : function() {
				return new fields.Ground(0, 0, 'grass');
			},
			apply : function(applier, col, row) {
				// applier was clicked over ground
				// place it
				applier.setPos(col, row);
				applier.place();
				// and return a new one
				return new fields.Ground(0, 0, 'grass');
			}
		},
		rail_cross : {
			cls : 'rails',
			el : $('<div class="toolitem"></div>'),
			ypos : "0px",
			applier : function() {
				return new fields.Rail(0, 0, 'cross');
			},
			apply : function(applier, col, row) {
				// applier was clicked over ground
				// place it
				applier.setPos(col, row);
				applier.place();
				// and release selection (no new applier)
				return null;
			}
		},
		rail_horizontal : {
			cls : 'rails',
			el : $('<div class="toolitem"></div>'),
			ypos : "-64px",
			applier : function() {
				return new fields.Rail(0, 0, 'horizontal');
			},
			apply : function(applier, col, row) {
				// applier was clicked over ground
				// place it
				applier.setPos(col, row);
				applier.place();
				// and return a new one
				return new fields.Rail(0, 0, 'horizontal');
			}
		},
		rail_vertical : {
			cls : 'rails',
			el : $('<div class="toolitem"></div>'),
			ypos : "-128px",
			applier : function() {
				return new fields.Rail(0, 0, 'vertical');
			},
			apply : function(applier, col, row) {
				// applier was clicked over ground
				// place it
				applier.setPos(col, row);
				applier.place();
				// and return a new one
				return new fields.Rail(0, 0, 'vertical');
			}
		},
		rail_curve_lb : {
			cls : 'rails',
			el : $('<div class="toolitem"></div>'),
			ypos : "-192px",
			applier : function() {
				return new fields.Rail(0, 0, 'curve_lb');
			},
			apply : function(applier, col, row) {
				// applier was clicked over ground
				// place it
				applier.setPos(col, row);
				applier.place();
				// and release selection (no new applier)
				return null;
			}
		},
		rail_curve_lt : {
			cls : 'rails',
			el : $('<div class="toolitem"></div>'),
			ypos : "-256px",
			applier : function() {
				return new fields.Rail(0, 0, 'curve_lt');
			},
			apply : function(applier, col, row) {
				// applier was clicked over ground
				// place it
				applier.setPos(col, row);
				applier.place();
				// and release selection (no new applier)
				return null;
			}
		},
		rail_curve_rt : {
			cls : 'rails',
			el : $('<div class="toolitem"></div>'),
			ypos : "-320px",
			applier : function() {
				return new fields.Rail(0, 0, 'curve_rt');
			},
			apply : function(applier, col, row) {
				// applier was clicked over ground
				// place it
				applier.setPos(col, row);
				applier.place();
				// and release selection (no new applier)
				return null;
			}
		},
		rail_curve_rb : {
			cls : 'rails',
			el : $('<div class="toolitem"></div>'),
			ypos : "-384px",
			applier : function() {
				return new fields.Rail(0, 0, 'curve_rb');
			},
			apply : function(applier, col, row) {
				// applier was clicked over ground
				// place it
				applier.setPos(col, row);
				applier.place();
				// and release selection (no new applier)
				return null;
			}
		},
		rail_switch_hlb : {
			cls : 'rails',
			el : $('<div class="toolitem"></div>'),
			ypos : "-448px",
			applier : function() {
				return new fields.Rail(0, 0, 'switch_hlb');
			},
			apply : function(applier, col, row) {
				// applier was clicked over ground
				// place it
				applier.setPos(col, row);
				applier.place();
				// and release selection (no new applier)
				return null;
			}
		},
		rail_switch_vlb : {
			cls : 'rails',
			el : $('<div class="toolitem"></div>'),
			ypos : "-512px",
			applier : function() {
				return new fields.Rail(0, 0, 'switch_vlb');
			},
			apply : function(applier, col, row) {
				// applier was clicked over ground
				// place it
				applier.setPos(col, row);
				applier.place();
				// and release selection (no new applier)
				return null;
			}
		},
		rail_switch_hlt : {
			cls : 'rails',
			el : $('<div class="toolitem"></div>'),
			ypos : "-576px",
			applier : function() {
				return new fields.Rail(0, 0, 'switch_hlt');
			},
			apply : function(applier, col, row) {
				// applier was clicked over ground
				// place it
				applier.setPos(col, row);
				applier.place();
				// and release selection (no new applier)
				return null;
			}
		},
		rail_switch_vrt : {
			cls : 'rails',
			el : $('<div class="toolitem"></div>'),
			ypos : "-640px",
			applier : function() {
				return new fields.Rail(0, 0, 'switch_vrt');
			},
			apply : function(applier, col, row) {
				// applier was clicked over ground
				// place it
				applier.setPos(col, row);
				applier.place();
				// and release selection (no new applier)
				return null;
			}
		},
		rail_switch_hrb : {
			cls : 'rails',
			el : $('<div class="toolitem"></div>'),
			ypos : "-704px",
			applier : function() {
				return new fields.Rail(0, 0, 'switch_hrb');
			},
			apply : function(applier, col, row) {
				// applier was clicked over ground
				// place it
				applier.setPos(col, row);
				applier.place();
				// and release selection (no new applier)
				return null;
			}
		},
		rail_switch_hrt : {
			cls : 'rails',
			el : $('<div class="toolitem"></div>'),
			ypos : "-768px",
			applier : function() {
				return new fields.Rail(0, 0, 'switch_hrt');
			},
			apply : function(applier, col, row) {
				// applier was clicked over ground
				// place it
				applier.setPos(col, row);
				applier.place();
				// and release selection (no new applier)
				return null;
			}
		},
		rail_switch_vlt : {
			cls : 'rails',
			el : $('<div class="toolitem"></div>'),
			ypos : "-832px",
			applier : function() {
				return new fields.Rail(0, 0, 'switch_vlt');
			},
			apply : function(applier, col, row) {
				// applier was clicked over ground
				// place it
				applier.setPos(col, row);
				applier.place();
				// and release selection (no new applier)
				return null;
			}
		},
		rail_switch_vrb : {
			cls : 'rails',
			el : $('<div class="toolitem"></div>'),
			ypos : "-896px",
			applier : function() {
				return new fields.Rail(0, 0, 'switch_vrb');
			},
			apply : function(applier, col, row) {
				// applier was clicked over ground
				// place it
				applier.setPos(col, row);
				applier.place();
				// and release selection (no new applier)
				return null;
			}
		},
		rail_signal : {
			cls : 'signal',
			el : $('<div class="toolitem"></div>'),
			ypos : "0px",
			applier : function() {
				var sign = new signals.Signal(0, 0, defs.Direction.UP);
				return sign;
			},
			apply : function(applier, col, row) {
				// applier was clicked over ground
				// place it
				applier.setPos(col, row);
				applier.place();
				// return new applier
				return new signals.Signal(0, 0, applier.direction);
			}
		},
		rail_switcher : {
			cls : 'switch',
			el : $('<div class="toolitem"></div>'),
			ypos : "0px",
			applier : function() {
				var swit = new signals.Switch(0, 0, defs.Direction.UP);
				return swit;
			},
			apply : function(applier, col, row) {
				// applier was clicked over ground
				// place it
				applier.setPos(col, row);
				applier.place();
				// return new applier
				return new signals.Switch(0, 0, applier.direction);
			}
		},
		train_locomotive : {
			cls : 'movables',
			el : $('<div class="toolitem"></div>'),
			ypos : "0px",
			applier : function() {
				var train = new movable.Train(0, 0, defs.Direction.UP);
				return train;
			},
			apply : function(applier, col, row) {
				// applier was clicked over ground
				// place it
				applier.setPos(col, row);
				applier.place();
				// return new applier
				return new movable.Train(0, 0, applier.toDirection);
			}
		}
	};

	/*
	 * PLACE AND HANDLE TOOL BAR ITEMS
	 */
	// create a placer for the given field
	toolbar.prepareApplier = function(field) {
		var div = $('<div class="field itemaction"></div>');
		div.css('opacity', '0.5');
		div.data('field', field);
		div.append(field.el);
		traintest.ground.append(div);
		return div;
	};

	// append toolbar entries and callbacks
	for ( var toolEntry in toolbar.toolBarEntries) {
		var cls = toolbar.toolBarEntries[toolEntry].cls;
		var ypos = toolbar.toolBarEntries[toolEntry].ypos;
		// configure generic properties
		var el = toolbar.toolBarEntries[toolEntry].el;
		el.addClass(cls);
		el.css('background-position-y', ypos);
		el.data('toolBarEntry', toolEntry);
		toolbar.bar.append(el);
		el
			.click(function(e) {
				// get toolbar entry
				var el = $(e.currentTarget);
				// remove existing applier
				if (toolbar.applier !== null) {
					toolbar.applier.remove();
					toolbar.applier = null;
				}
				// remove selectors
				toolbar.removeSelectors();
				// make a new instance
				var entry = el.data('toolBarEntry');
				var applierField = toolbar.toolBarEntries[entry].applier
					.call(this);
				if (applierField instanceof fields.FieldPosition) {
					// wrap the field into a applier container
					var applier = toolbar.prepareApplier(applierField);
					toolbar.applier = applier;
					var fnApply = toolbar.toolBarEntries[entry].apply;
					var cbFn = function(e) {
						// call applier function
						var f = new fields.FieldPosition(0, 0);
						f
							.setPosCss(toolbar.applier.position().left, toolbar.applier
								.position().top);
						var newField = fnApply.call(this, toolbar.applier
							.data('field'), f.column, f.row);
						// check the result
						if (newField === undefined || newField === null) {
							// applier remove
							toolbar.applier.remove();
						} else if (newField instanceof fields.FieldPosition
							&& newField !== toolbar.applier.data('field')) {
							// new applier
							toolbar.applier.remove();
							toolbar.applier = toolbar.prepareApplier(newField);
							toolbar.applier.click(toolbar.applier_cbFn);
						} else {
							// applier remains
							;
						}
					};
					// add callback
					toolbar.applier.click(cbFn);
					toolbar.applier_cbFn = cbFn;
				}
			});
	}

};
